package com.maker.generator.event.handler;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;

import com.maker.generator.entity.MetaGenAttr;
import com.maker.generator.entity.MetaGenConfig;
import com.maker.generator.entity.MetaGenConfigItem;
import com.maker.generator.entity.MetaGenDBInfo;
import com.maker.generator.entity.MetaGenObj;
import com.maker.generator.entity.MetaGenTable;
import com.maker.generator.event.GenerateEvent;
import com.maker.generator.utils.TransUtil;

import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;

public class GenerateHandler implements ApplicationListener<GenerateEvent>{
	private static Logger logger = LoggerFactory.getLogger(GenerateHandler.class);

	

	@Override
	public void onApplicationEvent(GenerateEvent event) {
		//generateHTML(new Long(event.getObjectId()), templateDir, event.getRootOutDir(), dataMap);
		
		switch (event.getType()){
			case GenerateEvent.GENERATE_TYPE_T2O:
				generateEntity(event.getTable(),event.getOptions());
				break;
			case GenerateEvent.GENERATE_TYPE_O2M:
				String rootOutDir = event.getRootOutDir();
				generateMAPPER(event.getObj(),event.getTable(),rootOutDir);
				break;
			case GenerateEvent.GENERATE_TYPE_ENTITY:
				//generateEntityString()
				break;
			default :
				break;
		}
		
	}
	
	private void generateEntity(MetaGenTable table,Map<String, Object> dataMap){
		
		
	}
	
	private void generateMAPPER(MetaGenObj obj,MetaGenTable table,String rootOutDir){
		
		Map<String,Object> dataMap = new HashMap<String,Object>();
		dataMap.put("entity", obj);
		dataMap.put("table", table);
		String templateName ="MetaMapper.ftl";
		String templateDir = rootOutDir+"themes"+File.separator+"Monitor"+File.separator+"generator"+File.separator+"metaTemplate";
		String outputFileDirName = rootOutDir+"themes"+File.separator+"Monitor"+File.separator+"generator"+File.separator+"result";
		String outputFileName = outputFileDirName+File.separator+obj.getObjName()+"Mapper";
		String pageSuffix=".xml";
		
		
		
		
		Map<String,Object> result =  generate(templateDir,templateName,outputFileDirName,outputFileName,pageSuffix,0, dataMap);
	}
	
	private List<String> resultBuffer(MetaGenObj obj,MetaGenDBInfo dbInfo){
		List<String> result = new ArrayList<String>();
		result.add("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
		result.add("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\" >");
		result.add("<mapper namespace="+obj.getObjTypeName()+">");
		//纯实体map
		List<String> entityMapper = new ArrayList<String>();
		entityMapper.add("<resultMap id=\""+obj.getObjName()+"PureMap\" type=\""+obj.getObjName()+"\">");
		//带关联对象的实体map
		List<String> entityWithRelationMapper = new ArrayList<String>();
		//关联对象实体map的map
		Map<String,List<String>> refRelationMapper = new HashMap<String,List<String>>();
		
		
		Map<String,List<String>> attrSqlMap = new HashMap<String,List<String>>();
		Map<String,List<String>> refAttrSelectorMap = new HashMap<String,List<String>>();
		Map<String,List<String>> objSelectorMap = new HashMap<String,List<String>>();
		entityWithRelationMapper.add("<resultMap id=\""+obj.getObjName()+"Map\" type=\""+obj.getObjName()+"\">");
		String tableName = "";
		List<String> baseColumn = new ArrayList<String>();
		List<String> baseWhere = new ArrayList<String>();
		List<String> insert = new ArrayList<String>();
		List<String> insert_attrList = new ArrayList<String>();
		List<String> insert_valueList = new ArrayList<String>();
		insert_valueList.add(") values (");
		List<String> update = new ArrayList<String>();
		
		List<String> update_FieldList = new ArrayList<String>();
		String updateWhere = new String();
		tableName = getConfigItemValueByKey(obj,MetaGenConfig.TABLE_NAME);
		if(("".equals(tableName)) || (tableName == null)){
			tableName =TransUtil.obj2TableName(obj);
		}
		insert.add("<insert id=\"save\" parameterType=\""+obj.getObjName()+"\" useGeneratedKeys=\"false\"  keyProperty=\"id\" keyColumn=\"id\">");
		if(MetaGenDBInfo.DBTYPE_ORACLE.equals(dbInfo.getDbType())){
			insert.add("<selectKey resultType=\"java.lang.Long\" keyProperty=\"id\" order=\"BEFORE\">");
			
			insert.add("	select sq_"+tableName+"_id.nextval as id from dual");
			insert.add("</selectKey>");
		}else{
			//mysql的不用加这个selectKey
		}
		insert_attrList.add("insert into "+tableName+"(");
		update.add("<update id = \"update\" parameterType=\""+obj.getObjName()+"\">");
		update.add("update "+tableName+" set");
		
		baseColumn.add("<sql id=\"Base_Column_List\">");
		baseWhere.add("<sql id=\"Base_Where_Clause\">");
		baseWhere.add("	<where>");
		baseWhere.add("		<trim prefixOverrides=\"and\">");
		
		
		
		
		for(MetaGenAttr attr : obj.getMetaAttrs()){
			switch (attr.getRelationShip()){
				case MetaGenAttr.RELATIONSHIP_1N:
					
					break;
				case MetaGenAttr.RELATIONSHIP_NN:
					
					break;
				case MetaGenAttr.RELATIONSHIP_N1:
					entityWithRelationMapper.add("<association javaType=\""+attr.getAttrShortTypeName()+"\" property=\""+attr.getAttrName()+"\" column=\""+attr.getAttrName()+"Id\" select=\"find"+attr.getAttrShortTypeName()+"ById\" />");
					insert_attrList.add(attr.getAttrName()+"Id ,");
					
					MetaGenObj refObj = new MetaGenObj();
					//TODO 先需要根据属性的全类型，去查找元对象
					//refObj = 
					if(refObj!=null && refObj.getMetaAttrs()!=null){
						String refTableName = getConfigItemValueByKey(refObj,MetaGenConfig.TABLE_NAME);
						if(refTableName == null || "".equals(refTableName)){
							refTableName = TransUtil.obj2TableName(refObj);
						}
						List<String> attrMapper = new ArrayList<String>();
						List<String> selector = new ArrayList<String>();
						String objPrimaryType = "";
						
						attrMapper.add("<resultMap id=\""+attr.getAttrName()+"Map\" type=\""+attr.getAttrShortTypeName()+"\">");
						//属性为引用对象时，建立相关引用对象的简单映射MAP，以及相应选择器
						List<String> sqlList = new ArrayList<String>();
						sqlList.add("<sql id=\""+refObj.getObjName()+"_Column_List\">");
						for(MetaGenAttr refObjAttr:refObj.getMetaAttrs()){
							switch (refObjAttr.getRelationShip()){
								case MetaGenAttr.RELATIONSHIP_1N:
									break;
								case MetaGenAttr.RELATIONSHIP_NN:
									break;
								case MetaGenAttr.RELATIONSHIP_N1:
									break;
								default:
									if("ID".equals(refObjAttr.getAttrName()) || "id".equals(refObjAttr.getAttrName())){
										attrMapper.add("<id column=\"id\" property=\"id\" />");
										
									}else{
										attrMapper.add("<result column=\""+refObjAttr.getAttrName()+"\" property=\""+refObjAttr.getAttrName()+"\" />");
									}
									break;
							}
							if("ID".equals(refObjAttr.getAttrName()) || "id".equals(refObjAttr.getAttrName())){
								objPrimaryType = refObjAttr.getAttrType();
							}
							sqlList.add(refObjAttr.getAttrName()+" as "+refObjAttr.getAttrName()+" ,");
							
						}
						String attrColumnTailer = sqlList.get(sqlList.size()-1);
						attrColumnTailer = attrColumnTailer.substring(0, attrColumnTailer.length()-1);
						sqlList.remove(sqlList.size()-1);
						sqlList.add(attrColumnTailer);
						sqlList.add("</sql>");
						attrSqlMap.put(refObj.getObjName()+"Column_List", sqlList);
						attrMapper.add("</resultMap>");
						
						selector.add("<select id=\"find"+TransUtil.upperCase(attr.getAttrName())+"ById\" resultMap=\""+attr.getAttrName()+"Map\" parameterType=\""+objPrimaryType+"\">");
						selector.add("	select");
						selector.add("		*");
						selector.add("	from "+refTableName+"");
						selector.add("	where id = #{"+attr.getAttrName()+"Id}");
						selector.add("</select>");
						refRelationMapper.put("relation_"+attr.getAttrName(), attrMapper);
						refAttrSelectorMap.put("find"+attr.getAttrShortTypeName()+"ById",selector);
					}
					break;
				default:
					//对应的数据库类型
					String fieldType = getConfigItemValueByKey(attr,MetaGenConfig.FIELD_TYPE);
					if(MetaGenDBInfo.DBTYPE_ORACLE.equals(dbInfo.getDbType())){
						if(("".equals(fieldType)) || (fieldType == null)){
							fieldType = TransUtil.javaType2OracleFieldType(attr.getAttrType());
						}
					}else{
						if(("".equals(fieldType)) || (fieldType == null)){
							fieldType = TransUtil.javaType2MysqlFieldType(attr.getAttrType());
						}
						
					}
					if("ID".equals(attr.getAttrName()) || "id".equals(attr.getAttrName())){
						entityMapper.add("<id column=\"id\" property=\"id\" />");
						entityWithRelationMapper.add("<id column=\"id\" property=\"id\" />");
						baseWhere.add("<if test=\"id != null\"> and id = #{id}</if>");
						updateWhere = "id=#{id, jdbcType="+fieldType+"}";
					}else{
						entityMapper.add("<result column=\""+attr.getAttrName()+"\" property=\""+attr.getAttrName()+"\" />");
						entityWithRelationMapper.add("<result column=\""+attr.getAttrName()+"\" property=\""+attr.getAttrName()+"\" />");
						baseWhere.add("<if test=\""+attr.getAttrName()+" != null\">and "+attr.getAttrName()+" = #{"+attr.getAttrName()+"}</if>");
						if("java.lang.String".equals(attr.getAttrType())){
							if(MetaGenDBInfo.DBTYPE_ORACLE.equals(dbInfo.getDbType())){
								baseWhere.add("<if test=\""+attr.getAttrName()+"Like != null\">and "+attr.getAttrName()+" like  \'%\'||#{"+attr.getAttrName()+"}||\'%\'</if>");
							}else{
								baseWhere.add("<if test=\""+attr.getAttrName()+"Like != null\">and "+attr.getAttrName()+" like CONCAT(\"%\",#{"+attr.getAttrName()+"Like},\"%\")</if>");
							}
						}
						update_FieldList.add(""+attr.getAttrName()+" = #{"+attr.getAttrName()+", jdbcType="+fieldType+"},");
					}
					
					insert_valueList.add("#{"+attr.getAttrName()+", jdbcType="+fieldType+"}, ");
					insert_attrList.add(attr.getAttrName()+" ,");
					
					
					baseColumn.add(attr.getAttrName()+" as "+attr.getAttrName()+" ,");
					baseWhere.add("<if test=\"id != null\"> and id = #{id}</if>");
					break;
			
			
			}
			
			
		}
		
		String baseColumnTailer = baseColumn.get(baseColumn.size()-1);
		baseColumnTailer = baseColumnTailer.substring(0, baseColumnTailer.length()-1);
		baseColumn.remove(baseColumn.size()-1);
		baseColumn.add(baseColumnTailer);
		baseColumn.add("</sql>");
		
		String insert_AttrTailer = insert_attrList.get(insert_attrList.size()-1);
		insert_AttrTailer = insert_AttrTailer.substring(0, insert_AttrTailer.length()-1);
		insert_attrList.remove(insert_attrList.size()-1);
		insert_attrList.add(insert_AttrTailer);
		
		String insert_ValueTailer = insert_valueList.get(insert_valueList.size()-1);
		insert_ValueTailer = insert_ValueTailer.substring(0, insert_ValueTailer.length()-1);
		insert_valueList.remove(insert_valueList.size()-1);
		insert_valueList.add(insert_ValueTailer);
		insert_valueList.add(")");
		insert.addAll(insert_attrList);
		insert.addAll(insert_valueList);
		insert.add("</insert>");
		
		String update_ColumnTailer = update_FieldList.get(update_FieldList.size()-1);
		update_ColumnTailer = update_ColumnTailer.substring(0, update_ColumnTailer.length()-1);
		update_FieldList.remove(update_FieldList.size()-1);
		update_FieldList.add(update_ColumnTailer);
		update.addAll(update_FieldList);
		update.add("where");
		update.add(updateWhere);
		
		
		baseWhere.add("		</trim>");
		baseWhere.add("	</where>");
		baseWhere.add("	<if test=\"sorting != null\">order by ${sorting}</if>");
		baseWhere.add("</sql>");
		
		entityMapper.add("</resultMap>");
		return result;
		
	}
	
	
	
//	StringWriter writer = new StringWriter();
//    String content = "你的名字${name}";
//
//    Configuration configuration = new Configuration();  
//    StringTemplateLoader stringLoader = new StringTemplateLoader();
//    stringLoader.putTemplate("contract", content);
//    configuration.setTemplateLoader(stringLoader);
//
//    Template template = configuration.getTemplate("contract","utf-8");  
//    Map<String,Object> root = new HashMap<String,Object>();    
//    root.put("name", "郭啸天");  
//    try {  
//        template.process(root, writer);  
//        System.out.println(writer.toString());    
//        response.getWriter().print(writer.toString());
//    } catch (TemplateException e) {  
//            e.printStackTrace();  
//    }
	
	private Map<String,Object>  generate(String stringTemplateBody,Map<String, Object> dataMap){
		Map<String,Object> renderResult = new HashMap<String, Object>();
		String result = "";
		
		String status = "success";
		StringWriter writer = new StringWriter();
        
		long startTime=System.currentTimeMillis();
        Configuration configuration = new Configuration();  
        StringTemplateLoader stringLoader = new StringTemplateLoader();
        stringLoader.putTemplate("stringTemplateName", stringTemplateBody);
        configuration.setTemplateLoader(stringLoader);  
        try {
        	Template template = configuration.getTemplate("stringTemplateName","utf-8");  
            template.process(dataMap, writer);  
            result =writer.toString();
            
        }catch (IOException e) {
        	
        	status = "errr:IO错误！";
			e.printStackTrace();
		}catch (TemplateException e) {  
			status = "errr:string模板渲染出错！";
            e.printStackTrace();  
		} 
        long endTime=System.currentTimeMillis();
        
        renderResult.put("costTime", (startTime-endTime)+"ms");
        renderResult.put("result", result);
        renderResult.put("status", status);
		return renderResult;
	}
	private Map<String,Object> generate(String templateDir,String templateName,String outputFileDirName,String outputFileName,String pageSuffix,int page,Map<String, Object> dataMap){
		Map<String,Object> gr = new HashMap<String, Object>();
		Boolean temMark = Boolean.TRUE;
		if(pageSuffix == null || ("".equals(pageSuffix))){
			pageSuffix = ".html";
		} 
		try {
			Configuration config = new Configuration();
			config.setDirectoryForTemplateLoading(new File(templateDir));
			config.setObjectWrapper(new DefaultObjectWrapper());
			Template template = config.getTemplate(templateName);
	        File outputFileDir = new File(outputFileDirName);  
	        // 创建文件夹，不存在则创建  
	        org.apache.commons.io.FileUtils.forceMkdir(outputFileDir);  
	        // 指定生成输出的文件  
	        if(page >= 1){
	        	pageSuffix ="_"+(page+1)+pageSuffix;
	        }
	        File output = new File(outputFileName+pageSuffix);  
	        Writer writer = new FileWriter(output);  
	        template.process(dataMap, writer);
	        writer.close(); 
		} catch (IOException e) {
			temMark = Boolean.FALSE; 
			e.printStackTrace();
		} catch (TemplateException e){
			temMark = Boolean.FALSE;
		}
		gr.put("mark", temMark);
		if(logger.isInfoEnabled()){	
			logger.info("------["+outputFileName+pageSuffix+"]生成状态:"+(Boolean.TRUE == temMark?"成功!":"失败"));
		}
		
		return gr;
	}
	/**
	 * 根据JAVA对象以及KEY，从配置里取相应
	 * @param obj
	 * @param key
	 * @return
	 */
	private String getConfigItemValueByKey(MetaGenObj obj,String key){
		String value="";
		if(obj.getConfig()!=null && obj.getConfig().getItems()!=null && obj.getConfig().getItems().size()>0){
			for(MetaGenConfigItem item:obj.getConfig().getItems()){
				if(key.equals(item.getItemKey())){
					value = item.getItemValue();
					break;
				}
			}
		}
		return value;
	}
	private String getConfigItemValueByKey(MetaGenAttr attr,String key){
		String value="";
		if(attr.getConfig()!=null && attr.getConfig().getItems()!=null && attr.getConfig().getItems().size()>0){
			for(MetaGenConfigItem item:attr.getConfig().getItems()){
				if(key.equals(item.getItemKey())){
					value = item.getItemValue();
					break;
				}
			}
		}
		return value;
	}

	
	
	
}
